package continuity;

/**
 * A játék karaktere, aki tudja, hogy éppen melyik Node-ban tartózkodik. 
 * Van „lendülete”, így képes az ugrásra. A játékban a felhasználó 
 * utasításainak megfelelően próbál meg mozogni, figyelembe véve 
 * környezete sajátosságait.
 * @author FornetTeam
 */
public class Character {
    /**
     * A karakter sorszáma.
     */
    private int nbr;
    /**
     * A Character lendülete. 
     * Ha talajon áll, akkor a lendülete 0. 
     * Ugrás hatására megnöveljük a lendületét, ha nincs felette akadály.
     * Emellett esésnél, azaz, ha nincs alatt talaj 
     * folyamatosan csökken a lendülete.
     */
    private int momentum;
    /**
     *  Éppen ebben a mezőben tartózkodik a karakter.
     * Az Node isHere nevú listájának megfelelő helyén 
     * jelezni kell, hogy itt vagyunk.
     */
    private Node now;
    /**
     * A karakter újjáéledési helye. Először a pálya kezdőpontja,
     * majd az utoljára felszedett kulcs mezője.
     */
    private Node reloadPosition;
    
    /**
     * A Character konstruktora.
     * @param nbr - A karakter sorszáma.
     */
    public Character(int nbr){
        momentum=0;
        this.nbr=nbr;
    }
    
    /**
     * A karakter lendületét növeli meg jumpValue értékkel, 
     * ha olyan mező van  alatta, amire nem tud lépni, 
     * azaz képes “elrugaszkodni” róla.
     */
    public void jump(){
        Node downNeighbor=now.getNeighbor(Direction.Down.toInt());
        Element e = downNeighbor.getElement();
        
        if(e.canIsHere()==false)
        {
            momentum+=Parameters.jumpValue;
        }
    }

    /**
     * A paraméterként átadott értéknek megfelelő irányba próbál meg a karakter
     * mozogni, amennyiben ez lehetséges. A karakter átállítja az aktuális 
     * pozícióját (Node now), valamint a mozgásban résztvevő mezők isHere 
     * értékeit is átállítja (a korábbi mező karaktersorszámnak megfelelő 
     * mezőjét hamisra, az új mező megfelelő mezőjét pedig igazra kell állítani).
     */
    public boolean move(Direction dir) {
        boolean ret = false;
        Node neighbor = now.getNeighbor(dir.toInt());
        if (neighbor != null){
            Element element = neighbor.getElement();  
            /**
            * Csak akkor mozgunk,
            * ha az adott mezőre léphet a karakter.
            */
            boolean canMove = element.canIsHere();
            if (canMove){
                ret = true;
                now.setIsHere(nbr, false);
                neighbor.setIsHere(nbr, true);
                now=neighbor;
                element.doSomething();
            }
        }
        return ret;
    }
    
    /**
     * Ha nincs alatta akadály, és nincs lendülete, akkor zuhan. Ha pozitív 
     * lendülete van, akkor felfele mozdul el (közben eggyel csökken a lendülete)
     * , amennyiben nincsen felette 
     * akadály. Ha felfele mozgás közben akadályba ütközik, akkor a lendülete 
     * lecsökken 0-ra, majd lefele kezd esni. A karakter átállítja az aktuális
     * pozícióját (Node now), valamint a mozgásban résztvevő mezők isHere 
     * értékeit is átállítja (a korábbi mező karaktersorszámnak megfelelő
     * mezőjét hamisra, az új mező megfelelő mezőjét pedig igazra kell állítani).
     */
    public Direction fall(){
        Direction ret = null;
        if(momentum>0) {
            //felfele mozgunk
            Node up=now.getNeighbor(Direction.Up.toInt());
            if(up!=null) {
                Element e=up.getElement();
                if(e.canIsHere()==true) {
                    ret = Direction.Up;
                    now.setIsHere(nbr, false);
                    up.setIsHere(nbr, true);
                    now=up;
                    momentum--;
                    e.doSomething();
                }
                else {
                    momentum=0;
                }
            }
            else {
                momentum=0;
            }
        }
        else {
            Node down=now.getNeighbor(Direction.Down.toInt());
            Element e=down.getElement();
            if(e.canIsHere()==true) {
                //ha tudunk esünk
                ret = Direction.Down;
                now.setIsHere(nbr, false);
                down.setIsHere(nbr, true);
                now=down;
                e.doSomething();
            }
        }
        
        return ret;
    }

    /**
     * Az újjáéledési hely (reloadPosition attribútum) beállítása.
     * @param reloadPosition Az újjáéledés helye.
     */
    public void setReloadPosition(Node reloadPosition){
        this.reloadPosition = reloadPosition;
    }
    
    /**
     * A now attribútum a reloadPosition-nel lesz egyenlő.
     * Ezen felül updateli a két résztvevő Node megfelelő isHere változóit is.
     */
    public void reloadCharacter(){                    
        now.setIsHere(nbr, false);
        reloadPosition.setIsHere(nbr, true);
        now = reloadPosition;
    }
    
    /**
     * A karakter kezdőpozíciójának beállítása, emellett a kezdő Node
     * megfelelő isHere tagjának beállítása a setIsHere függvénnyel.
     * @param n A karakter kezdőhelye.
     */
    public void setPosition(Node n) {
        now=n;
        now.setIsHere(nbr, true);
        reloadPosition=n;
    }
}
